\section{The Stanza Testbench Simulation}

Chipper's Stanza based testbench is the first line of defense against simple bugs in your design. The Stanza testbench uses several unique Chipper constructs to perform this. To see how this works, let's first explore a simple example.

\subsection{Stanza Testbench Example}

Below is the \verb+ByteSelector.stanza+ module definition from the previous tutorial and the corresponding Chipper test harness.

\begin{stanza}
defmodule ByteSelector :
  input  in:     UInt<32>
  input  offset: UInt<2>
  output out:    UInt<8>

  when offset === UInt(0) :
     out := in[7,0]
  else when offset === UInt(1) :
     out := in[15, 8]
  else when offset === UInt(2) :
     out := in[23,16]
  else :
     out := in[31,24]

deftester ByteSelectorTests (c:ByteSelector) :
  val test_in = 12345678
  for t in 0 to 4 do :
    poke(this, c.io.in,     test_in)
    poke(this, c.io.offset, t)
    step(this, 1)
    expect(this, c.io.out, (test_in >> (t * 8)) & 0xFF)
\end{stanza}

In the test harness \verb+ByteSelectorTests+ we see that the test portion is written in Stanza with some Chipper constructs inside a \verb+Tester+ class definition. The device under test is passed to us as a parameter \verb+c+. 

In the \verb+for+ loop, the assignments for each input of the \verb+ByteSelector+ is set to the appropriate values using \verb+poke+. For this particular example, we are testing the \verb+ByteSelector+ by hardcoding the input to some known value and checking if each of the 4 offsets returns the appropriate byte. To do this, on each iteration we generate appropriate inputs to the module and tell the simulation to assign this value to the input of the device we are testing \verb+c+:

\begin{stanza}
val test_in = 12345678
for t in 0 to 4 do :
  ;; set in of the DUT to be some known word
  poke(this, c.io.in,     test_in)
  ;; set the offset of the DUT
  poke(this, c.io.offset, t)
  ...
\end{stanza}

Next we step the circuit.  We next advance the simulation by calling the \verb+step+ function. This effectively advances the simulation one clock cycle in the presence of sequential logic. 

\begin{stanza}
step(this, 1)
\end{stanza}

Finally, we check for expected outputs.
In this case, we check the expected output of \verb+ByteSelector+ as follows:

\begin{stanza}
expect(this, c.io.out, (test_in >> (t * 8)) & 0xFF)
\end{stanza}

This defines the reference output expected for this particular cycle of the simulation. Since the circuit we are testing is purely combinational, we expected that the output we define appears on any advancement of the simulation.  The \verb+expect+ function will record either true or false after checking if the output generates the expected reference output. The results of successive \verb+expect+'s are anded into a \verb+Tester+ field called \verb+ok+ which starts out as \verb+true+.  The value of the \verb+ok+ field determines the success or failure of the tester execution.

Actually \verb+expect+ is defined in terms of \verb+peek+ roughly as follows:

\begin{stanza}
def expect (tester:Tester, data: Bits, expected: BigInt) :
  peek(tester, data) == expected
\end{stanza}

where \verb+peek+ gets the value of a signal from the DUT.

\subsection{Simulation Debug Output}

Now suppose we run the testbench for the \verb+ByteSelector+ defined previously. To do this, \verb+cd+ into the \verb+$DIR/problems+ directory and run \verb+make ByteSelector+.

When we run the testbench, we will notice that the simulation produces debug output every time the \verb+step+ function is called. Each of these calls gives the state of the inputs and outputs to the \verb+ByteSelector+ and whether the check between the reference output and expected output matched as shown below:

\begin{bash}
STARTING ../emulator/problems/ByteSelector
---
POKE ByteSelector__io_in <- 12345678
POKE ByteSelector__io_offset <- 0
STEP 1 <- 0
PEEK ByteSelector__io_out -> 0x4e
EXPECT ByteSelector__io_out <- 78 == 78 PASS
POKE ByteSelector__io_in <- 12345678
POKE ByteSelector__io_offset <- 1
STEP 1 <- 0
PEEK ByteSelector__io_out -> 0x61
EXPECT ByteSelector__io_out <- 97 == 97 PASS
...
POKE ByteSelector__io_in <- 12345678
POKE ByteSelector__io_offset <- 3
STEP 1 <- 0
PEEK ByteSelector__io_out -> 0x00
EXPECT ByteSelector__io_out <- 0 == 0 PASS
PASSED   // Final pass assertion
[success] Total time: 6 s, completed Feb 23, 2014 9:52:22 PM
\end{bash}

Also notice that there is a final pass assertion "PASSED" at the end which corresponds to the \verb+allGood+ at the very end of the testbench. In this case, we know that the test passed since the allGood assertion resulted in a "PASSED". In the event of a failure, the assertion would result in a "FAILED" output message here.

\subsection{General Testbench}

In general, the stanza testbench should have the following rough structure:

\begin{itemize}
\item Set inputs using \verb+poke+
\item Advance simulation using \verb+step+
\item Check expected values using \verb+expect+ (and/or \verb+peek+)
\item Repeat until all appropriate test cases verified
\end{itemize}

For sequential modules we may want to delay the output definition to the appropriate time as the \verb+step+ function implicitly advances the clock one period in the simulation. Unlike Verilog, you do not need to explicitly specify the timing advances of the simulation; Chipper will take care of these details for you.

\section{\problem{Max2 Testbench}}

In this assignment, write a tester for the \verb+Max2+ circuit:

\begin{stanza}
defmodule Max2 :
  input  in0 : UInt<8>
  input  in1 : UInt<8>
  output out : UInt<8>
  out := mux(in0 > in0, in0, in1)
\end{stanza}

\noindent
found in \verb+$TUT_DIR/problems/Max2.stanza+ by filling in the following tester:

\begin{stanza}
deftester Max2Tests (c: Max2) :
  for i in 0 to 10 do :
    ;; FILL THIS IN HERE
    poke(this, c.io.in0, 0)
    poke(this, c.io.in1, 0)
    ;; FILL THIS IN HERE
    step(this, 1)
    expect(this, c.io.out, 1)
\end{stanza}

\noindent 
using random integers generated as follows:

\begin{stanza}
;; returns random int in 0..lim-1
val in0 = rand(lim) 
\end{stanza}

\noindent
Run 

\begin{bash}
make Max2.out
\end{bash}

\noindent 
until the circuit passes your tests.

\section{Limitations of the Testbench}

The Chipper testbench works well for simple tests and small numbers of simulation iterations. However, for larger test cases, the Chipper testbench quickly becomes more complicated and slower simply due to the inefficiency of the infrastructure. For these larger and more complex test cases, we recommend using the C++ emulator or Verilog test harnesses which run faster and can handle more rigorous test cases.

